import src from './source';
import * as _ from './common';
import { calculateFormula } from './formula';
import * as FieldUtil from './fieldUtil';
import * as DetailUtil from './detailUtil';
import * as LinkageControl from './linkageControl';
import { calculateDetailFormulaNew } from './FormulaNew';
import * as AI from './analyzeData';

//联动触发逻辑
export default class Linkage {
    triType = -1;   //1：字段值变化触发  2：页面加载触发  3：新增行触发  4、删除行触发
    layoutStore = {};
    commonParam = {};
    showAI = false;
    triInfo = {};

    constructor(triType) {
        this.triType = parseInt(triType);
        this.layoutStore = src.layoutStore;
        this.commonParam = src.globalStore.commonParam;
        this.showAI = src.globalStore.urlParams && src.globalStore.urlParams.showAI === "1";
    }

    /************ 联动总控,触发入口,非异步联动全部计算完后只做一次结果变更，单类型异步联动只发一次请求，联动考虑明细单行及所有行情况 ************/
    doTrigger = (tableMark, triFieldid, rowIndex) => {
        triFieldid = triFieldid == null || typeof triFieldid === "undefined" ? "" : triFieldid.toString();
        rowIndex = rowIndex == null || typeof rowIndex === "undefined" ? "-1" : rowIndex.toString();
        const nodetype = parseInt(this.commonParam.nodetype || 0);
        if ((this.triType === 3 || this.triType === 4) && tableMark.indexOf("detail_") === -1)
            return;
        if (nodetype === 3 && this.triType !== 2)    //归档节点除页面加载执行部分联动外其它都不执行
            return;
        this.triInfo = { triType: this.triType, tableMark, triFieldid, rowIndex };
        const { propFileCfg, linkageCfg, fieldAttrMap } = this.layoutStore;
        //仅显示，不允许编辑
        const onlyShow = parseInt(this.commonParam.isviewonly || 0) === 1 || parseInt(this.commonParam.isaffirmance || 0) === 1;
        const iscreate = parseInt(this.commonParam.iscreate || 0);
        /************ 是否触发联动判断 *************/
        let needTriRowRule = false;
        let needTriColRule = false;
        let needTriFieldMath = false;
        let needTriFormula = false;
        let needTriSelectChange = false;
        let needTriViewAttr = false;
        let needTriFieldSql = false;
        let needTriDateTime = false;
        let needTriDataInput = false;
        if (this.triType === 1) {      //字段值变更
            if (tableMark === "main") {
                needTriFieldMath = true;
            } else if (tableMark.indexOf("detail_") > -1) {
                const triFieldAttr = fieldAttrMap.get(triFieldid);
                if (triFieldAttr.htmltype === 1 && triFieldAttr.detailtype !== 1) {   //数值字段触发行列规则
                    needTriRowRule = true;
                    needTriColRule = true;
                }
            }
            needTriFormula = true;
            needTriSelectChange = true;
            needTriViewAttr = true;
            needTriFieldSql = true;
            needTriDateTime = true;
            needTriDataInput = true;
        } else if (this.triType === 2) {    //页面加载
            if ((!onlyShow && propFileCfg.tri_rowRule_edit === "1") || (onlyShow && propFileCfg.tri_rowRule_view === "1"))
                needTriRowRule = true;
            if (!onlyShow) {
                needTriFieldMath = true;
                needTriFormula = true;
                needTriFieldSql = true;
                needTriDateTime = true;
                needTriDataInput = true;
            }
            needTriColRule = true;
            needTriViewAttr = true; //已办也需要执行显示属性联动隐藏
            needTriSelectChange = true;     //已办需要执行复选框相关联动显示
        } else if (this.triType === 3) {    //新增行
            needTriRowRule = true;
            needTriColRule = true;
            needTriFormula = true;
            needTriSelectChange = true;
            needTriViewAttr = true;
            needTriFieldSql = true;
            needTriDateTime = true;
            needTriDataInput = true;
        } else if (this.triType === 4) {    //删除行
            needTriColRule = true;
            needTriFormula = true;
        }
        /************ 分发执行各类联动 *************/
        let changeDatas = {};
        let fieldVars = {};
        let changeVars = {};
        if (needTriRowRule) {     //行规则
            const rowRule_result = this.executeRowRule(tableMark, triFieldid, rowIndex) || {};
            _.merge(changeDatas, rowRule_result);
        }
        if (needTriColRule) {     //列规则
            const colRule_result = this.executeColRule(tableMark, triFieldid) || {};
            _.merge(changeDatas, colRule_result["changeDatas"]);
            _.merge(changeVars, colRule_result["changeVars"]);
        }
        if (needTriFieldMath) {   //字段赋值
            const fieldMath_result = this.executeFieldMath(triFieldid) || {};
            _.merge(changeDatas, fieldMath_result);
        }
        if (needTriFormula) {     //公式
            const formula_result = this.executeFormula(tableMark, triFieldid, rowIndex) || {};
            _.merge(changeDatas, formula_result);
        }
        if (needTriSelectChange) {    //选择框联动
            const selectChange_result = this.controlSelectChange(tableMark, triFieldid, rowIndex) || {};
            _.merge(changeDatas, selectChange_result["changeDatas"]);
            _.merge(fieldVars, selectChange_result["fieldVars"]);
        }
        if (needTriViewAttr) {    //显示属性联动
            const viewAttr_result = this.controlViewAttr(tableMark, triFieldid, rowIndex) || {};
            _.merge(fieldVars, viewAttr_result["fieldVars"]);
            _.merge(changeVars, viewAttr_result["changeVars"]);
        }
        //控制字段类型变更联动
        const fieldTypeChange_result = this.controlFieldTypeChange(tableMark, triFieldid, rowIndex) || {};
        _.merge(changeDatas, fieldTypeChange_result["changeDatas"]);
        _.merge(fieldVars, fieldTypeChange_result["fieldVars"]);
        
        /************ 非异步联动统一修改 *************/
        //console.log("---linkageResult---", changeDatas, fieldVars, changeVars);
        if (!_.isEmpty(changeVars))
            this.layoutStore.batchControlVariableMap(changeVars);   //必须先赋合计值再赋字段修改值，解决添加行动作的行规则赋值字段再合计，线程顺序问题
        if (!_.isEmpty(changeDatas) || !_.isEmpty(fieldVars)) {
            const stepid = AI.generateStepId(AI.TYPE_LINKAGE_SYNC, { ...this.triInfo });
            this.layoutStore.changeMoreFieldData(changeDatas, fieldVars, stepid);
        }
        /***************** 触发异步联动 **************/
        if (needTriFieldSql) {    //SQL联动
            const fieldSql_triInfo = this.generateFieldSqlTriInfo(tableMark, triFieldid, rowIndex);
            this.sendLinkageAjax(fieldSql_triInfo, "fieldsql");
        }
        if (needTriDateTime) {    //日期时间计算
            const dateTime_triInfo = this.generateDateTimeTriInfo(tableMark, triFieldid, rowIndex);
            this.sendLinkageAjax(dateTime_triInfo, "datetime");
        }
        if (needTriDataInput) {   //字段联动
            const dataInput_triInfo = this.generateDataInputTriInfo(tableMark, triFieldid, rowIndex);
            this.sendLinkageAjax(dataInput_triInfo, "datainput");
        }
    }

    //判断明细表是否不在模板上
    judgeDetailUnExistTemplate = (detailMark) => {
        const { cellInfo } = this.layoutStore;
        const { isSourceLayout } = src.globalStore;
        if (isSourceLayout) {
            const detailIndex = parseInt(detailMark.substring(7)) - 1;
            return window.jQuery("table#oTable" + detailIndex).length === 0;
        } else {
            return !_.has(cellInfo, ["subPanelInfo", detailMark]);
        }
    }

    //判断字段是否不在模板上
    judgeFieldUnExistTemplate = (fieldid) => {
        const { fieldAttrMap, cellInfo } = this.layoutStore;
        if (_.has(cellInfo, ["fieldCellInfo", fieldid]) && fieldAttrMap.has(fieldid) && fieldAttrMap.get(fieldid).viewattr > 0)
            return false;
        else
            return true;
    }

    //计算明细字段合计值
    getDetailFieldSumValue = (tableMark, fieldid) => {
        //let sum = 0;
        let expression = "0";
        const { detailMap } = this.layoutStore;
        const { rowInfoArr, detailData } = detailMap.get(tableMark);
        rowInfoArr.map(info => {
            let fieldNumValue = 0;
            if (detailData.has(`field${fieldid}_${info.rowIndex}`))
                fieldNumValue = detailData.get(`field${fieldid}_${info.rowIndex}`).numValue;
            //sum += fieldNumValue;
            if (fieldNumValue < 0) {
                expression += fieldNumValue;
            } else {
                expression = expression + "+" + fieldNumValue;
            }
        });
        const result = FieldUtil.calExpressionResult(expression);
        return result;
    }

    //执行行规则运算
    executeRowRule = (tableMark, triFieldid, rowIndex) =>{
        const { linkageCfg,fieldAttrMap,detailMap,propFileCfg } = this.layoutStore;
        const rowCalCfg = linkageCfg.rowCalCfg || {};
        const triInfo = {};
        if(this.triType === 1){
            triFieldid in rowCalCfg && rowCalCfg[triFieldid].map(cfg =>{
                triInfo[cfg.assignField] = {expression:cfg.config, tableMark:tableMark, rowIndexStr:rowIndex};
            });
        }else if(this.triType === 2){
            _.forIn(rowCalCfg, (v,k) =>{
                if(k === "rowCalAssignInfo")
                    return true;  
                v && v.map(cfg =>{
                    const assignField = cfg.assignField;
                    if(assignField in triInfo || !fieldAttrMap.has(assignField))
                        return true;    //不需要重复添加
                    const detailMark = fieldAttrMap.get(assignField).tableMark;
                    const detailObj = detailMap.get(detailMark);
                    triInfo[assignField] = {expression:cfg.config, tableMark:detailMark, rowIndexStr:detailObj.allRowIndexStr};
                });
            });
        }else if(this.triType === 3){
            _.forIn(rowCalCfg, (v,k) =>{
                if(k === "rowCalAssignInfo")
                    return true;
                v && v.map(cfg =>{
                    const assignField = cfg.assignField;
                    if(!fieldAttrMap.has(assignField))
                        return true;
                    const detailMark = fieldAttrMap.get(assignField).tableMark;
                    if(assignField in triInfo || tableMark !== detailMark)
                        return true;    //不需要重复添加，只触发当前明细涉及的行规则
                    triInfo[assignField] = {expression:cfg.config, tableMark:tableMark, rowIndexStr:rowIndex};
                });
            });
        }
        const changeDatas = {};
        !_.isEmpty(triInfo) && _.forIn(triInfo, (v,key) =>{     //循环配置
            const { tableMark,expression,rowIndexStr } = v;
            if(this.judgeFieldUnExistTemplate(key))   //赋值字段不在模板不计算行规则
                return true;
            let needCal = true;
            expression.match(/detailfield_\d+/g).map(fieldstr =>{
                if(this.judgeFieldUnExistTemplate(fieldstr.substring(12)))      //任一取值字段不在模板的不计算行规则
                    needCal = false;
            });
            needCal && !!rowIndexStr && rowIndexStr.split(",").map(rowIndex =>{    //循环行
                let curExpression = expression;
                const reg = new RegExp("detailfield_\\d+", "g");
                curExpression.match(reg).map(fieldstr =>{
                    let fieldval = FieldUtil.getFieldValue(fieldstr.substring(12), rowIndex, true);
                    if(fieldval < 0)
                        fieldval = `(${fieldval})`;     //负数参与计算加括号
                    const reg1 = new RegExp(fieldstr+"(?!\d)", "g");		//正向否定预查，后面跟的不是数字才匹配
                    curExpression = curExpression.replace(reg1, fieldval);
                });
                let result = FieldUtil.calExpressionResult(curExpression);
                if(this.triType === 3 && parseFloat(result) === 0 && propFileCfg.rowRule_addRow_empty !== "1")   //新增行触发的行规则计算结果为0的赋空值
                    result = "";
                changeDatas[`field${key}_${rowIndex}`] = {value:result};
            });
        });
        return changeDatas;
    }

    //执行列规则运算
    executeColRule = (tableMark, triFieldid) =>{
        const { linkageCfg,fieldAttrMap,detailMap,propFileCfg } = this.layoutStore;
        const colCalCfg = linkageCfg.colCalCfg || {};
        const mainCalCfg = linkageCfg.mainCalCfg || {};
        const triInfo = {};
        if(this.triType === 1){
            const needSum = triFieldid in colCalCfg;
            const sumMainFieldid = mainCalCfg[triFieldid];
            if(needSum || !!sumMainFieldid)
                triInfo[triFieldid] = {tableMark, needSum, sumMainFieldid};
        }else if(this.triType === 2 || this.triType === 3 || this.triType === 4){
            detailMap.forEach((detailObj,detailMark) =>{
                if(this.triType === 2 || ((this.triType === 3 || this.triType === 4) && detailMark === tableMark)){
                    _.forIn(detailObj.fieldInfo, (v,fieldid) =>{
                        if(v.htmltype === 1 && v.detailtype !== 1){
                            const needSum = fieldid in colCalCfg;
                            const sumMainFieldid = mainCalCfg[fieldid];
                            if(needSum || !!sumMainFieldid)
                                triInfo[fieldid] = {tableMark:detailMark, needSum, sumMainFieldid}
                        }
                    });
                }
            });
        }
        let changeDatas = {};
        let changeVars = {};
        !_.isEmpty(triInfo) && _.forIn(triInfo, (v,fieldid) =>{
            const { tableMark,needSum,sumMainFieldid } = v;
            if(this.judgeDetailUnExistTemplate(tableMark))           
                return true;   //明细表不存在模板上不计算列规则
            if(this.judgeFieldUnExistTemplate(fieldid))   
                return true;   //字段不在模板不计算列规则
            let sum = this.getDetailFieldSumValue(tableMark, fieldid);
            //明细列合计
            if(needSum){
                const formatSumValue = FieldUtil.convertNumberValue(sum, fieldAttrMap.get(fieldid));
                changeVars[`sum${fieldid}`] = formatSumValue;
            }
            //合计赋值主字段
            if(!!sumMainFieldid){
                const { rowInfoArr } = detailMap.get(tableMark);
                if(sum === 0 && rowInfoArr.length === 0 && propFileCfg.colRule_noRow_empty !== "1")   //明细无数据时，提示必填用
                    sum = "";
                changeDatas[`field${sumMainFieldid}`] = {value:sum};
            }
        });
        return {changeDatas, changeVars};
    }

    //执行字段赋值运算
    executeFieldMath = (triFieldid) =>{
        const { linkageCfg,fieldAttrMap } = this.layoutStore;
        const fieldMathCfg = linkageCfg.fieldMathCfg || {};
        const triInfo = {};
        if(this.triType === 1){
            triFieldid in fieldMathCfg && fieldMathCfg[triFieldid].map(cfg =>{
                triInfo[cfg.assignField] = {expression:cfg.config, relateFields:cfg.relateFields};
            });
        }else if(this.triType === 2){
            _.forIn(fieldMathCfg, (v,k) =>{
                v && v.map(cfg =>{
                    triInfo[cfg.assignField] = {expression:cfg.config, relateFields:cfg.relateFields};
                });
            });
        }
        const changeDatas = {};
        _.forIn(triInfo, (v, assignField) =>{
            if(this.judgeFieldUnExistTemplate(assignField))
                return true;
            let expression = v.expression;
            v.relateFields && v.relateFields.map(fieldid =>{
                if(!fieldAttrMap.has(fieldid))    //字段不存在时不替换，执行时做抛错处理
                    return "";
                let fieldval = FieldUtil.getFieldValue(fieldid, -1, true);
                if(fieldval < 0)
                    fieldval = `(${fieldval})`;     //负数参与计算加括号
                const reg = new RegExp("\\$"+fieldid+"\\$", "g");
                expression = expression.replace(reg, fieldval);
            });
            const result = FieldUtil.calExpressionResult(expression);
            changeDatas[`field${assignField}`] = {value:result};
        });
        return changeDatas;
    }

    //执行公式运算
    executeFormula = (tableMark, triFieldid, rowIndex) =>{
        const { dataJson,cellInfo,propFileCfg } = this.layoutStore;
        const formulaCfg = dataJson.formula || {};
        if(this.triType === 3 || this.triType === 4){
            //新增和删除明细行时触发执行新版公式
            setTimeout(() => {calculateDetailFormulaNew(tableMark, rowIndex)}, 50);
        }
        if(_.isEmpty(formulaCfg))
            return;
        const triInfo = [];
        if(this.triType === 1){
            const relateFormula = _.get(cellInfo, ["fieldCellInfo", triFieldid, "relateFormula"]);
            relateFormula && relateFormula.map(formulaKey =>{
                if(formulaKey in formulaCfg){
                    const cfg = formulaCfg[formulaKey];
                    //触发字段为主表，赋值字段为明细需计算明细所有行公式
                    const triRowMark = (parseInt(rowIndex) === -1 && cfg["destcell"].indexOf("DETAIL_") > -1) ? "all" : rowIndex;
                    triInfo.push({formulaKey, triRowMark});
                }
            });
        }else if(this.triType === 2 && propFileCfg.tri_formula_all === "1"){
            _.forIn(formulaCfg, (cfg,formulaKey) =>{
                const triRowMark = formulaKey.indexOf("DETAIL_") > -1 ? "all" : -1;
                triInfo.push({formulaKey, triRowMark});
            });
        }else if(this.triType === 3){    //新增明细触发
            _.forIn(formulaCfg, (cfg,formulaKey) =>{
                if(formulaKey.indexOf(tableMark.toUpperCase()) > -1){
                    triInfo.push({formulaKey, triRowMark:rowIndex});
                }else if(formulaKey.indexOf("DETAIL_") === -1 && cfg["formulatxt"].indexOf(tableMark.toUpperCase()) > -1){    //当前明细字段参与公式计算同时赋值给主字段  
                    triInfo.push({formulaKey, triRowMark:-1});
                }
            });

        }else if(this.triType === 4){    //删除明细触发
            _.forIn(formulaCfg, (cfg,formulaKey) =>{
                if(formulaKey.indexOf("DETAIL_") === -1 && cfg["formulatxt"].indexOf(tableMark.toUpperCase()) > -1){    //当前明细字段参与公式计算同时赋值给主字段  
                    triInfo.push({formulaKey, triRowMark:-1});
                }
            });
        }
        if(triInfo.length === 0)   
            return;
        const changeDatas = calculateFormula(triInfo);
        return changeDatas;
    }

    //控制选择框联动
    controlSelectChange = (tableMark, triFieldid, rowIndex) =>{
        const onlyShow = parseInt(this.commonParam.isviewonly || 0) === 1 || parseInt(this.commonParam.isaffirmance || 0) === 1;
        const { fieldAttrMap,detailMap } = this.layoutStore;
        const triInfo = {};
        if(this.triType === 1){
            const attr = fieldAttrMap.get(triFieldid);
            if(!attr || attr.htmltype !== 5 || _.get(attr, ["selectattr", "childfieldid"]) === 0)
                return;
            triInfo[triFieldid] = {attr:attr, rowIndexStr:rowIndex};
        }else if(this.triType === 2 ){
            fieldAttrMap.forEach((attr,fieldid) =>{
                if(attr.htmltype !== 5 || _.get(attr, ["selectattr", "childfieldid"]) === 0)
                    return true;
                const tableMark = attr.tableMark;
                const rowIndexStr = tableMark.indexOf("detail") > -1 ? detailMap.get(tableMark).allRowIndexStr : "-1";
                triInfo[fieldid] = {attr:attr, rowIndexStr:rowIndexStr};
            });
        }else if(this.triType === 3){
            const detailObj = detailMap.get(tableMark);
            _.forIn(detailObj.fieldInfo, (attr,fieldid) =>{
                if(attr.htmltype !== 5 || _.get(attr, ["selectattr", "childfieldid"]) === 0)
                    return true;
                triInfo[fieldid] = {attr:attr, rowIndexStr:rowIndex};
            });
        }
        const changeDatas = {};
        const fieldVars = {};
        !_.isEmpty(triInfo) && _.forIn(triInfo, (v,triFieldid) =>{
            if(this.judgeFieldUnExistTemplate(triFieldid))
                return true;
            const { attr,rowIndexStr } = v;
            const tableMark = attr.tableMark;
            const childFieldid = _.get(attr, ["selectattr", "childfieldid"]);
            const childFieldObj = fieldAttrMap.get(childFieldid.toString());
            const childFieldItemList = childFieldObj && _.get(childFieldObj, ["selectattr", "selectitemlist"]);
            if(!childFieldItemList || _.isEmpty(childFieldItemList) || rowIndexStr === "")
                return true;
            rowIndexStr.split(",").map(rowIndex =>{
                let childitemid = "";
                const triFieldValue = FieldUtil.getFieldValue(triFieldid, rowIndex);
                triFieldValue !== "" && _.get(attr, ["selectattr", "selectitemlist"]).map(item =>{
                    if(item.selectvalue === parseInt(triFieldValue))
                        childitemid = item.childitemid;
                });
                const optionRange = childitemid.split(",");   //IE下可变数组不支持includes方法
                //计算联动子字段选中值逻辑：有效值且在range范围内直接选中，无有效值则找range范围内的选择框默认值，无默认值则置空
                let childFieldValue = FieldUtil.getFieldValue(childFieldid, rowIndex);     //联动前子字段选中的值
                if(childFieldValue !== ""){
                    const childValueArr = childFieldValue.split(",");
                    let childValueNew = "";
                    childValueArr.map(value =>{
                        if(_.indexOf(optionRange, value) === -1)
                            return true;    //不在选项范围内选中值无效
                        let isValid = false;    //校验封存逻辑
                        childFieldItemList.map(item =>{
                            if(item.selectvalue.toString() === value && (item.cancel !== 1 || (item.cancel === 1 && onlyShow)))
                                isValid = true;
                        });
                        if(isValid)
                            childValueNew += `,${value}`;
                    });
                    childFieldValue = childValueNew;
                }
                childFieldValue === "" && childFieldItemList.map(item =>{   //空值取range范围内选择框默认值
                    const selectvalue = item.selectvalue.toString();
                    if(item.isdefault === 1 && item.cancel !== 1 && _.indexOf(optionRange, selectvalue) > -1)
                        childFieldValue += `,${selectvalue}`;
                });
                if(childFieldValue.length > 0 && childFieldValue.substring(0,1) === ",")
                    childFieldValue = childFieldValue.substring(1);
                const fieldMark = tableMark.indexOf("detail_") > -1 ? `field${childFieldid}_${rowIndex}` : `field${childFieldid}`;
                changeDatas[fieldMark] = {value: childFieldValue};
                fieldVars[fieldMark] = {optionRange: optionRange};
            });
        });
        return {changeDatas, fieldVars};
    }

    //控制显示属性联动
    controlViewAttr = (tableMark, triFieldid, rowIndex) =>{
        const { linkageCfg,fieldAttrMap,detailMap } = this.layoutStore;
        const viewAttrCfg = linkageCfg.viewAttrCfg || {};
        const triInfo = {};
        if(this.triType === 1){
            const fieldMark = `${triFieldid}_${tableMark.indexOf("detail_")>-1 ? 1 : 0}`;
            if(fieldMark in viewAttrCfg)
                triInfo[triFieldid] = {cfg:viewAttrCfg[fieldMark], rowIndexStr:rowIndex};
        }else if(this.triType === 2){
            _.forIn(viewAttrCfg, (cfg,k) =>{
                const fieldid = k.split("_")[0];
                const isDetail = k.split("_")[1] === "1";
                if(!fieldAttrMap.has(fieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(fieldid).tableMark;
                const rowIndexStr = isDetail ? detailMap.get(belTableMark).allRowIndexStr : "-1";
                triInfo[fieldid] = {cfg:cfg, rowIndexStr:rowIndexStr};
            });
        }else if(this.triType === 3){
            _.forIn(viewAttrCfg, (cfg,k) =>{
                const fieldid = k.split("_")[0];
                const isDetail = k.split("_")[1] === "1";
                if(!fieldAttrMap.has(fieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(fieldid).tableMark;
                if(belTableMark === tableMark && isDetail)
                    triInfo[fieldid] = {cfg:cfg, rowIndexStr:rowIndex};
            });
        }
        const fieldVars = {};
        const changeVars = {};
        !_.isEmpty(triInfo) && _.forIn(triInfo, (v,triFieldid) =>{
            const { cfg,rowIndexStr } = v;
            !!rowIndexStr && rowIndexStr.split(",").map(rowIndex =>{
                const triFieldValue = FieldUtil.getFieldValue(triFieldid, rowIndex);
                let triAction = {};
                _.forIn(cfg, (curAction,triKey) =>{
                    if(triKey === "relateFields")
                        return true;
                    if(this.judgeViewAttrTriCondition(triKey,triFieldValue))
                        triAction = {...triAction, ...curAction};
                });
                cfg["relateFields"].map(field=>{
                    const fieldid = field.split("_")[0];
                    const isDetail = field.split("_")[1] == "1";
                    const fieldMark = isDetail ? `field${fieldid}_${rowIndex}` : `field${fieldid}`;
                    let changeViewAttr = -1;
                    if(_.has(triAction, field)){      //更改字段属性
                        changeViewAttr = parseInt(_.get(triAction, field) || -1);
                        if(changeViewAttr === 1)    //可编辑
                            changeViewAttr = 2;
                        else if(changeViewAttr === 2)   //必填
                            changeViewAttr = 3;
                        else if(changeViewAttr === 3)   //只读
                            changeViewAttr = 1;
                    }

                    fieldVars[fieldMark] = {viewAttr: -1};
                    changeVars[`${fieldMark}_viewAttr`] = -1;
                    if(changeViewAttr <= 3)
                        fieldVars[fieldMark] = {viewAttr: changeViewAttr};
                    //显示属性联动隐藏不能存fieldObj对象中，优化性能
                    if(changeViewAttr === 4 || changeViewAttr === 5)
                        changeVars[`${fieldMark}_viewAttr`] = changeViewAttr;
                });
            });
        });
        return {fieldVars, changeVars};
    }

    //显示属性联动判断条件是否满足
    judgeViewAttrTriCondition = (triKey, fieldvalue) =>{
        let pass = false;
        const triArr = triKey.split("|");
        if(triArr.length != 2)
            return false;
        const relation = triArr[0];
        const triValue = `,${triArr[1]},`;
        const realValue = `,${fieldvalue},`;
        switch(parseInt(relation)){
            case 0:     //属于
                pass = triValue.indexOf(realValue) > -1;
                break;
            case 1:     //不属于
                pass = triValue.indexOf(realValue) === -1;
                break;
            case 2:     //包含
                pass = realValue.indexOf(triValue) > -1;
                break;
            case 3:     //不包含
                pass = realValue.indexOf(triValue) === -1;
                break;
            case 4:     //选中
                pass = fieldvalue == "1";
                break;
            case 5:     //不选中
                pass = fieldvalue != "1";
                break;
        }
        return pass;
    }

    //联动控制字段类型(财务选择框联动浏览按钮、人力将时间变为选择框等等)
    controlFieldTypeChange = (tableMark, triFieldid, rowIndex) =>{
        let linkageCfg = {};
        const { fnaInfo,hrmInfo,fieldAttrMap,detailMap } = this.layoutStore;
        if(fnaInfo && fnaInfo.belFna === true)
            linkageCfg = {...linkageCfg, ...fnaInfo.linkageCfg};
        if(hrmInfo && hrmInfo.belHrm === true)
            linkageCfg = {...linkageCfg, ...hrmInfo.linkageCfg};
        if(_.isEmpty(linkageCfg))
            return;

        const triInfo = [];
        if(this.triType === 1){
            const isDetail = tableMark.indexOf("detail_") > -1;
            const triFieldMark = isDetail ? `${triFieldid}_1` : `${triFieldid}_0`;
            if(triFieldMark in linkageCfg)
                triInfo.push({triFieldMark, rowIndexStr:rowIndex});
        }else if(this.triType === 2){
            _.forIn(linkageCfg, (v,triFieldMark) =>{
                const triFieldid = triFieldMark.split("_")[0];
                const isDetail = triFieldMark.split("_")[1] === "1";
                if(!fieldAttrMap.has(triFieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(triFieldid).tableMark;
                if(isDetail && !detailMap.has(belTableMark))
                    return true;
                const rowIndexStr = isDetail ? detailMap.get(belTableMark).allRowIndexStr : "-1";
                triInfo.push({triFieldMark, rowIndexStr});
            });
        }else if(this.triType === 3){
            _.forIn(linkageCfg, (v,triFieldMark) =>{
                const triFieldid = triFieldMark.split("_")[0];
                const isDetail = triFieldMark.split("_")[1] === "1";
                if(!fieldAttrMap.has(triFieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(triFieldid).tableMark;
                if(belTableMark === tableMark && isDetail)
                    triInfo.push({triFieldMark, rowIndexStr:rowIndex});
            });
        }
        const iscreate = parseInt(this.commonParam.iscreate || 0);
        const changeDatas = {};
        const fieldVars = {};
        triInfo.length > 0 && triInfo.map(triCfg =>{
            const { triFieldMark,rowIndexStr } = triCfg;
            const triFieldid = triFieldMark.split("_")[0];
            const isDetail = triFieldMark.split("_")[1] === "1";
            !!rowIndexStr && rowIndexStr.split(",").map(rowIndex =>{
                const fieldvalue = FieldUtil.getFieldValue(triFieldid, rowIndex);
                if(fieldvalue === "" || !_.has(linkageCfg, [triFieldMark, fieldvalue]))
                    return "";
                _.get(linkageCfg, [triFieldMark, fieldvalue]).map(cfg =>{    //数组，可以多个
                    const { fieldid,defValueObj="",changeType,selectOption } = cfg;
                    const _fieldid = fieldid.split("_")[0];
                    const fieldMark = isDetail ? `field${_fieldid}_${rowIndex}` : `field${_fieldid}`;
                    if(this.triType === 1 && !hrmInfo.belHrm)      //只有值变更才读取默认值，新增行默认值后端运算好
                        changeDatas[fieldMark] = defValueObj;
                    const changeFieldType = changeType.indexOf("-") > -1 ? changeType : `3-${changeType}`;  //默认为浏览按钮类型兼容财务
                    const changeFieldTypeSelectOption = selectOption || {};
                    fieldVars[fieldMark] = {changeFieldType, changeFieldTypeSelectOption};
                });
            });
        });
        return {changeDatas, fieldVars};
    }

    //生成SQL联动触发信息
    generateFieldSqlTriInfo = (tableMark, triFieldid, rowIndex) =>{
        const { linkageCfg,propFileCfg,fieldAttrMap,detailMap } = this.layoutStore;
        const triInfo = {};
        const fieldSqlCfg = linkageCfg.fieldSqlCfg || {};
        if(_.isEmpty(fieldSqlCfg))
            return {};
        if(this.triType === 1){
            triFieldid in fieldSqlCfg && fieldSqlCfg[triFieldid].map(cfg =>{
                const { assignField,config,relateFields } = cfg;
                if(this.judgeFieldUnExistTemplate(assignField))
                    return true;
                let rowIndexStr = rowIndex;
                const assignFieldBelMark = fieldAttrMap.get(assignField).tableMark;
                if(tableMark === "main" && assignFieldBelMark.indexOf("detail_")>-1)        //明细SQL取主表字段需联动所有明细行
                    rowIndexStr = detailMap.get(assignFieldBelMark).allRowIndexStr;
                const otherParams = {assignfields: [assignField]};
                triInfo[config] = {triFieldid:triFieldid, relateFields:relateFields, rowIndexStr:rowIndexStr, triTableMark:tableMark, otherParams};
            });
        }else if(this.triType === 2){
            _.forIn(fieldSqlCfg, (v,k) =>{
                v && v.map(cfg =>{
                    const { assignField,config,relateFields } = cfg;
                    if(this.judgeFieldUnExistTemplate(assignField))
                        return true;
                    const belTableMark = fieldAttrMap.get(assignField).tableMark;
                    if(belTableMark === "main" || propFileCfg.tri_fieldSql_detail === "1"){
                        const rowIndexStr = belTableMark.indexOf("detail_") > -1 ? detailMap.get(belTableMark).allRowIndexStr : "-1";
                        const otherParams = {assignfields: [assignField]};
                        triInfo[config] = {triFieldid:"", relateFields:relateFields, rowIndexStr:rowIndexStr, triTableMark:belTableMark, otherParams};
                    }
                });
            });
        }else if(this.triType === 3){
            _.forIn(fieldSqlCfg, (v,k) =>{
                v && v.map(cfg =>{
                    const { assignField,config,relateFields } = cfg;
                    if(this.judgeFieldUnExistTemplate(assignField))
                        return true;
                    const belTableMark = fieldAttrMap.get(assignField).tableMark;
                    if(belTableMark === tableMark){
                        const otherParams = {assignfields: [assignField]};
                        triInfo[config] = {triFieldid:"", relateFields:relateFields, rowIndexStr:rowIndex, triTableMark:belTableMark, otherParams};
                    }
                });
            });
        }
        return triInfo;
    }

    //生成日期时间计算触发信息
    generateDateTimeTriInfo = (tableMark, triFieldid, rowIndex) =>{
        const { linkageCfg,propFileCfg,fieldAttrMap,detailMap } = this.layoutStore;
        const triInfo = {};
        const fieldDateCfg = linkageCfg.fieldDateCfg || {};
        if(_.isEmpty(fieldDateCfg))
            return {};
        if(this.triType === 1){
            triFieldid in fieldDateCfg && fieldDateCfg[triFieldid].map(cfg =>{
                const { assignField,config,relateFields } = cfg;
                if(this.judgeFieldUnExistTemplate(assignField))
                    return true;
                triInfo[config] = {triFieldid:triFieldid, relateFields:relateFields, rowIndexStr:rowIndex, triTableMark:tableMark};
            });
        }else if(this.triType === 2){
            _.forIn(fieldDateCfg, (v,k) =>{
                v && v.map(cfg =>{
                    const { assignField,config,relateFields } = cfg;
                    if(this.judgeFieldUnExistTemplate(assignField))
                        return true;
                    const belTableMark = fieldAttrMap.get(assignField).tableMark;
                    if(belTableMark === "main" || propFileCfg.tri_dateTime_detail === "1"){
                        const rowIndexStr = belTableMark.indexOf("detail_") > -1 ? detailMap.get(belTableMark).allRowIndexStr : "-1";
                        triInfo[config] = {triFieldid:"", relateFields:relateFields, rowIndexStr:rowIndexStr, triTableMark:belTableMark};
                    }
                });
            });
        }else if(this.triType === 3){
            _.forIn(fieldDateCfg, (v,k) =>{
                v && v.map(cfg =>{
                    const { assignField,config,relateFields } = cfg;
                    if(this.judgeFieldUnExistTemplate(assignField))
                        return true;
                    const belTableMark = fieldAttrMap.get(assignField).tableMark;
                    if(belTableMark === tableMark)
                        triInfo[config] = {triFieldid:"", relateFields:relateFields, rowIndexStr:rowIndex, triTableMark:belTableMark};
                });
            });
        }
        return triInfo;
    }

    //生成字段联动触发信息
    generateDataInputTriInfo = (tableMark, triFieldid, rowIndex) =>{
        const { linkageCfg,propFileCfg,fieldAttrMap,detailMap } = this.layoutStore;
        const triInfo = {};
        const dataInputCfg = linkageCfg.dataInputCfg || {};
        if(_.isEmpty(dataInputCfg))
            return {};
        if(this.triType === 1){
            triFieldid in dataInputCfg && dataInputCfg[triFieldid].map(cfg =>{
                const { assignField,config,relateFields,otherParams } = cfg;
                triInfo[config] = {triFieldid:triFieldid, relateFields:relateFields, rowIndexStr:rowIndex, triTableMark:tableMark, otherParams};
            });
        }else if(this.triType === 2){
            const iscreate = parseInt(this.commonParam.iscreate || 0);
            _.forIn(dataInputCfg, (v,triFieldid) =>{
                if(!fieldAttrMap.has(triFieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(triFieldid).tableMark;
                const isDetail = belTableMark.indexOf("detail_") > -1;
                if(iscreate === 1 || (!isDetail && propFileCfg.tri_dataInput_main === "1") || (isDetail && propFileCfg.tri_dataInput_detail === "1")){
                    const rowIndexStr = isDetail ? detailMap.get(belTableMark).allRowIndexStr : "-1";
                    v && v.map(cfg =>{
                        const { assignField,config,relateFields,otherParams } = cfg;
                        triInfo[config] = {triFieldid:triFieldid, relateFields:relateFields, rowIndexStr:rowIndexStr, triTableMark:belTableMark, otherParams};
                    });
                }
            });
        }else if(this.triType === 3){
            _.forIn(dataInputCfg, (v,triFieldid) =>{
                if(!fieldAttrMap.has(triFieldid))
                    return true;
                const belTableMark = fieldAttrMap.get(triFieldid).tableMark;
                if(belTableMark === tableMark){
                    v && v.map(cfg =>{
                        const { assignField,config,relateFields,otherParams } = cfg;
                        triInfo[config] = {triFieldid:triFieldid, relateFields:relateFields, rowIndexStr:rowIndex, triTableMark:belTableMark, otherParams};
                    });
                }
            });
        }
        return triInfo;
    }

    //生成联动后台请求参数
    generateReqLinkageParams = (triInfo, linkageType) =>{
        const { fieldAttrMap } = this.layoutStore;
        let params = {
            requestid: this.commonParam.requestid,
            workflowid: this.commonParam.workflowid,
            nodeid: this.commonParam.nodeid,
            formid: this.commonParam.formid,
            isbill: this.commonParam.isbill,
            triSource: this.triType,
            showAI: this.showAI ? "1" : "0",
        };
        let linkageid = "";
        !_.isEmpty(triInfo) && _.forIn(triInfo, (v,key) =>{
            const { triFieldid,relateFields,rowIndexStr,triTableMark,otherParams } = v;
            if(rowIndexStr === "")
                return true;
            const assignfields = otherParams && otherParams.assignfields || [];
            linkageid += key+",";
            params[`triFieldid_${key}`] = triFieldid;
            //params[`relateField_${key}`] = relateFields.toString();
            params[`rowIndexStr_${key}`] = rowIndexStr;
            params[`triTableMark_${key}`] = triTableMark;
            rowIndexStr.split(",").map(rowIndex =>{     //存在计算明细所有行情况
                //字段联动,需要触发字段值
                if(linkageType === "datainput"){
                    const triFieldMark = triTableMark.indexOf("detail_")>-1 ? `field${triFieldid}_${rowIndex}` : `field${triFieldid}`;
                    params[triFieldMark] = FieldUtil.getFieldValue(triFieldid, rowIndex);
                }
                //相关参与计算字段值
                relateFields.map(fieldid =>{
                    if(!fieldAttrMap.has(fieldid))
                        return true;
                    const fieldAttr = fieldAttrMap.get(fieldid);
                    const fieldMark = fieldAttr.isDetail ? `field${fieldid}_${rowIndex}` : `field${fieldid}`;
                    if(fieldMark in params)     //已取值不重复获取
                        return true;
                    params[fieldMark] = FieldUtil.getFieldValue(fieldid, rowIndex);
                });
                //赋值字段为自定义浏览框的需要传依赖字段值
                params = {...params, ...this.generateCustomBrowserDependParams(assignfields, rowIndex)};
            });
        });
        params["linkageid"] = linkageid !== "" ? linkageid.substring(0, linkageid.length-1) : "";
        return params;
    }

    //生成自定义浏览按钮字段依赖的字段值信息，传递给接口算出名称
    generateCustomBrowserDependParams = (fieldidArr,rowIndex) =>{
        const customParams = {};
        const { fieldAttrMap } = this.layoutStore;
        fieldidArr && fieldidArr.forEach(fieldid =>{
            const fieldAttr = fieldAttrMap.get(fieldid) || {};
            const { htmltype,detailtype,browserattr,isDetail } = fieldAttr;
            if(htmltype === 3 && (detailtype === 161 || detailtype === 162)){
                if(browserattr && browserattr.hasOwnProperty('cusDependShip') && browserattr.cusDependShip.length > 0){
                    const fieldMark = isDetail && parseInt(rowIndex) >= 0 ? `field${fieldid}_${rowIndex}` : `field${fieldid}`;
                    const dependValues = {};                
                    browserattr.cusDependShip.forEach(item =>{
                        const dependFieldValue = FieldUtil.getFieldValue(item.fieldid, rowIndex);
                        dependValues[item.key] = dependFieldValue;
                    });
                    customParams[`customDepend_${fieldMark}`] = JSON.stringify(dependValues);
                }
            }
        });
        return customParams;
    }

    //发送ajax异步请求服务器，获取联动结果并赋值
    sendLinkageAjax = (triInfo, linkageType) =>{
        if(_.isEmpty(triInfo))
            return;
        const { fieldAttrMap,propFileCfg,detailMap } = this.layoutStore;
        const iscreate = parseInt(this.commonParam.iscreate || 0);
        const reqInfoArr = new Array();
        //页面加载触发时，配置项控制是否拆分请求发送
        if(this.triType === 2 && propFileCfg.split_req_linkageData === "1"){
            _.forIn(triInfo, (cfg,key) =>{
                const singleTriInfo = {[key] : cfg};
                reqInfoArr.push(this.generateReqLinkageParams(singleTriInfo, linkageType));
            });
        }else{
            reqInfoArr.push(this.generateReqLinkageParams(triInfo, linkageType));
        }
        reqInfoArr.length > 0 && reqInfoArr.map(params =>{
            if(!params.linkageid)
                return true;
            const orderInfo = LinkageControl.generateKeyOrder(linkageType, params);
            let API_FUNCTION = null;
            if(linkageType === "datainput")
                API_FUNCTION = src.API_REQ.reqDataInputResult(params);
            else if(linkageType === "fieldsql")
                API_FUNCTION = src.API_REQ.reqFieldSqlResult(params);
            else if(linkageType === "datetime")
                API_FUNCTION = src.API_REQ.reqDateTimeResult(params);
            API_FUNCTION.then(data => {
                try{
                    data = LinkageControl.removeInvalidResponse(orderInfo, data);
                    //字段联动，主表联动明细，是否先删除已有明细
                    if(linkageType === "datainput" && this.triType === 1){
                        let delDetailMap = {};
                        !_.isEmpty(data) && _.forIn(data, (v,k) =>{
                            //主表联动明细
                            const addRows = v["addDetailRow"] || {};
                            const entryid = k.replace("assignInfo_","");
                            const needDelRow = triInfo[entryid].otherParams && triInfo[entryid].otherParams.isdel == "1";
                            if(needDelRow && !_.isEmpty(addRows)){     //先删除新增的明细行
                                let detailMarkArr = Object.keys(addRows);
                                detailMarkArr.length > 0 && detailMarkArr.map(detailMark=>{
                                    let delRowArr = [];
                                    const detailObj = detailMap.get(detailMark);
                                    const { rowInfo } = detailObj;
                                    !_.isEmpty(rowInfo) && rowInfo.forEach((info,rowKey) =>{
                                        if(parseInt(info.get("keyid") || 0) <= 0 && info.get("fromLinkage") === true)
                                            delRowArr.push(rowKey.substring(4));
                                    });
                                    if(delRowArr.length > 0){
                                        delDetailMap[detailMark] = delRowArr;
                                    }
                                });
                            }
                        });
                        if(Object.keys(delDetailMap).length > 0){
                            _.forIn(delDetailMap, (delRowArr,detailMark) =>{
                                DetailUtil.delAssignRow(detailMark, delRowArr);
                            });
                        }
                    }
                    //联动结果赋值，字段联动需先给主字段赋值再添加明细行
                    const changeDatas = {};
                    const addRowInfo = [];
                    const linkageSql = [];
                    !_.isEmpty(data) && _.forIn(data, (v,k) =>{
                        if(_.isEmpty(v))
                            return true;
                        let changeValue = v["changeValue"];
                        //字段联动,主表联动明细
                        if(linkageType === "datainput" && (this.triType === 1 || (this.triType === 2 && iscreate === 1))){
                            const addRows = v["addDetailRow"];
                            !_.isEmpty(addRows) && _.forIn(addRows, (rowDatas,detailMark) =>{
                                rowDatas && rowDatas.map(rowData =>{
                                    addRowInfo.push({detailMark, rowData});
                                });
                            });
                        }
                        //联动赋值
                        _.forIn(changeValue, (valueInfo, key) =>{
                            const fieldArr = key.split("_");
                            const fieldid = fieldArr[0].substring(5);
                            const rowIndex = fieldArr.length>1 ? fieldArr[1] : "-1";
                            if(fieldAttrMap.has(fieldid)){
                                const fieldAttr = fieldAttrMap.get(fieldid);
                                const fieldMark = fieldAttr.isDetail ? `field${fieldid}_${rowIndex}` : `field${fieldid}`;
                                changeDatas[fieldMark] = valueInfo;
                            }
                        });
                        //联动执行过的SQL集合
                        if(this.showAI && !!v.linkageSql)
                            linkageSql.push(v.linkageSql);
						if (v.resultOutOfLimit==true){
                            window.WfForm.showMessage("联动结果集数量超出限制，请检查字段联动设置！");
                        }
                    });
                    //字段值赋值
                    let stepid = 0;
                    if(this.showAI){
                        const asyncParams = {linkageType, linkageSql, reqParams:params, reqResult:data};
                        stepid = AI.generateStepId(AI.TYPE_LINKAGE_ASYNC, {...this.triInfo, ...asyncParams});
                    }
                    this.layoutStore.changeMoreFieldData(changeDatas, {}, stepid);
                    //记录主表联动明细的数据，行号+行数据
                    const addRowConvertInfo = [];
                    //添加明细行
                    addRowInfo.map(item =>{
                        const detailIndex = DetailUtil.addRow(item.detailMark, item.rowData, true);
                        const convertInfo = {
                            'detailIndex': detailIndex,
                            'rowData': item.rowData,
                        }
                        addRowConvertInfo.push(convertInfo);
                    });
                    //联动赋值完成后，浏览按钮类型变更，异步请求重新赋值
                    this.generateConvertDatas(changeDatas, addRowConvertInfo);
                }catch(e){
                    /* eslint no-console: 0 */
                    if(window.console)  console.error("sendLinkageAjax "+linkageType+" Exception:", params, data, e);
                }
            });
        });
    }

    //生成浏览按钮类型转换信息
    generateConvertDatas = (changeDatas = {}, addRowConvertInfo = []) => {
        const convertDatas = [];
        //非主表联动明细数据
        let fieldMark = "";
        for (fieldMark in changeDatas) {
            this.getConvertDatas(fieldMark, changeDatas[fieldMark].value, convertDatas);
        }
        //主表联动明细数据
        addRowConvertInfo && addRowConvertInfo.map(item => {
            !_.isEmpty(item.rowData) && _.forIn(item.rowData, (v, k) => {
                if (k.indexOf("field") > -1) {
                    const fieldMark = k + "_" + item.detailIndex;
                    this.getConvertDatas(fieldMark, v.value, convertDatas);
                }
            });

        });
        //浏览按钮类型变更数据不为空，则异步请求重新赋值
        if (!_.isEmpty(convertDatas)) {
            this.sendConvertTypeAjax(convertDatas);
        }
    }

    getConvertDatas = (fieldMark = "", fieldvalue = "", convertDatas = []) => {
        const fieldAttr = FieldUtil.getFieldAttr(fieldMark);
        if (_.isEmpty(fieldAttr))
            return;
        const tableMark = fieldAttr.tableMark;
        const fieldObj = FieldUtil.getFieldObj(fieldMark, tableMark);
        const fieldid = this.getFieldid(fieldMark);
        if (fieldObj && fieldObj.variable.has("changeFieldType")) {
            const changeFieldType = fieldObj.variable.get("changeFieldType");
            const convertInfo = {
                requestid: this.commonParam.requestid,
                formid: this.commonParam.formid,
                isbill: this.commonParam.isbill,
                fieldid: fieldid,
                fieldvalue: fieldvalue,
                destFieldid: fieldMark,
                browserType: changeFieldType,
            };
            convertDatas.push(convertInfo);
        }
    };

    //发送ajax异步请求服务器，获取浏览按钮类型转换结果，并赋值
    sendConvertTypeAjax = (convertDatas = []) => {
        if (_.isEmpty(convertDatas))
            return;
        const params = {
            arrayInfo: JSON.stringify(convertDatas),
        }
        src.API_REQ.getBrowserInfo(params).then(data => {
            if (data && data.result) {
                var jsonMsgs = JSON.parse(data.result);
                for (var idx = 0; idx < jsonMsgs.length; idx++) {
                    var jsonMsg = jsonMsgs[idx];
                    var fieldMark = jsonMsg.destFieldid;
                    var valueInfo = jsonMsg.destFieldValue;
                    if (valueInfo.value) {
                        valueInfo.value = valueInfo.value.trim();
                    }
                    const changeDatas = {};
                    changeDatas[fieldMark] = valueInfo;
                    const stepid = AI.generateStepId(AI.TYPE_LINKAGE_ASYNC);
                    this.layoutStore.changeMoreFieldData(changeDatas, {}, stepid);
                }
            }
        });
    }

    //获取字段ID
    getFieldid = (fieldMark) => {
        if (fieldMark.indexOf("_") > -1)
            fieldMark = fieldMark.substring(0, fieldMark.indexOf("_"));
        if (fieldMark.indexOf("field") > -1)
            fieldMark = fieldMark.substring(5);
        return fieldMark;
    }
}